#include <iostream>
#include <string>
#include <unistd.h>
#include "Thread.hpp"
#include "lockGuard.hpp"
#include "myThread.hpp"
#include "myLockGuard.hpp"
using namespace std;

// 细节：
// 1. 凡是访问同一个临界资源的线程，都要进行加锁保护，而且必须加同一把锁，这个是一个游戏规则，不能有例外
// 2. 每一个线程访问临界区之前，得加锁，加锁本质是给 临界区 加锁，加锁的粒度尽量要细一些
// 3. 线程访问临界区的时候，需要先加锁->所有线程都必须要先看到同一把锁->锁本身就是公共资源->锁如何保证自己的安全？-> 加锁和解锁本身就是原子的！
// 4. 临界区可以是一行代码，可以是一批代码，a. 线程可能被切换吗？当然可能， 不要特殊化加锁和解锁，还有临界区代码。
//    b. 切换会有影响吗？不会，因为在我不在期间，任何人都没有办法进入临界区，因为他无法成功的申请到锁！因为锁被我拿走了！
// 5. 这也正是体现互斥带来的串行化的表现，站在其他线程的角度，对其他线程有意义的状态就是：锁被我申请(持有锁)，锁被我释放了(不持有锁)， 原子性就体现在这里
// 6. 解锁的过程也被设计成为原子的！
// 7. 锁 的 原理的理解

// // 临界资源
int tickets = 1000;                                // 全局变量，共享对象
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 这是我在外边定义的锁

// class TData
// {
// public:
//     TData(const string &name, pthread_mutex_t *mutex):_name(name), _pmutex(mutex)
//     {}
//     ~TData()
//     {}
// public:
//     string _name;
//     // pthread_mutex_t *_pmutex;
// };

void threadRoutine(void *args)
{
    std::string message = static_cast<const char *>(args);
    while (true)
    {
        // pthread_mutex_lock(&mutex); // 加锁，是一个让不让你通过的策略
        {
            myLockGuard lockguard(&mutex); // RAII 风格的锁
            if (tickets > 0)
            {
                usleep(2000);
                cout << message << " get a ticket: " << tickets-- << endl; // 临界区
            }
            else
            {
                break;
            }
        }

        // 我们抢完一张票的时候，我们还要有后续的动作
        // usleep(13);
    }
    // adfasdf
    // asdfasdf
    // {
    //     LockGuard lockguard(&mutex); // RAII 风格的锁
    //     asdf
    //     asdf
    // }
    // asdfas
    // dfasd 
    // fasdfasdf
}

// void threadRun(void *args)
// {
//     std::string message = static_cast<const char *>(args);
//     int cnt = 10;
//     while (cnt)
//     {
//         cout << "我是一个线程, " << message << ", cnt: " << cnt-- << endl;
//         sleep(1);
//     }
// }

int main()
{
    myThread t1(1, threadRoutine, (void *)"hellobit1");
    myThread t2(2, threadRoutine, (void *)"hellobit2");
    myThread t3(3, threadRoutine, (void *)"hellobit3");
    myThread t4(4, threadRoutine, (void *)"hellobit4");

    t1.run();
    t2.run();
    t3.run();
    t4.run();

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    // cout << "thread name: " << t1.threadname() << " thread id: " << t1.threadid() << ",thread status: " << t1.status() << std::endl;
    // cout << "thread name: " << t2.threadname() << " thread id: " << t2.threadid() << ",thread status: " << t2.status() << std::endl;

    // t1.run();
    // t2.run();
    // cout << "thread name: " << t1.threadname() << " thread id: " << t1.threadid() << ",thread status: " << t1.status() << std::endl;
    // cout << "thread name: " << t2.threadname() << " thread id: " << t2.threadid() << ",thread status: " << t2.status() << std::endl;

    // t1.join();
    // t2.join();
    // cout << "thread name: " << t1.threadname() << " thread id: " << t1.threadid() << ",thread status: " << t1.status() << std::endl;
    // cout << "thread name: " << t2.threadname() << " thread id: " << t2.threadid() << ",thread status: " << t2.status() << std::endl;

    // pthread_mutex_t mutex;
    // pthread_mutex_init(&mutex, nullptr);

    // pthread_t tids[4];
    // int n = sizeof(tids)/sizeof(tids[0]);
    // for(int i = 0; i < n; i++)
    // {
    //     char name[64];
    //     snprintf(name, 64, "thread-%d", i+1);
    //     TData *td = new TData(name, &mutex);
    //     pthread_create(tids+i, nullptr, threadRoutine, td);
    // }

    // for(int i = 0; i < n; i++)
    // {
    //     pthread_join(tids[i], nullptr);
    // }

    // pthread_mutex_destroy(&mutex);
    return 0;
}